package com.maychat.controller;

import com.maychat.config.AppConfig;
import com.maychat.config.Consts;
import com.maychat.controller.base.BaseController;
import com.maychat.enums.ContactType;
import com.maychat.enums.MessageType;
import com.maychat.exception.BusinessException;
import com.maychat.exception.NoAuthException;
import com.maychat.pojo.ChatMessage;
import com.maychat.pojo.Result;
import com.maychat.pojo.UserInfoToken;
import com.maychat.pojo.extended.Message;
import com.maychat.service.ChatMessageService;
import com.maychat.utils.StringTools;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

@Slf4j
@RestController
@RequestMapping("/chat")
public class ChatController extends BaseController {

    @Autowired
    private ChatMessageService chatMessageService;
    @Autowired
    private AppConfig appConfig;

    @Autowired
    HttpServletResponse resp;

    @PostMapping("/sendMessage")
    public Result sendMessage(
            @NotBlank String contactId,
            @NotBlank String messageContent,
            @NotNull Integer messageType,
            Long fileSize, String fileName, Integer fileType) {
        UserInfoToken tokenObj = getTokenObj();
        MessageType type = MessageType.getByOrdinal(messageType);
        Integer[] allowedTypes = {MessageType.CHAT.ordinal(), MessageType.MEDIA_CHAT.ordinal()};
        if (type == null || !Arrays.asList(allowedTypes).contains(messageType))
            throw new BusinessException();
        ChatMessage chatMessage = new ChatMessage();
        chatMessage.setContactId(contactId);
        chatMessage.setContactType(ContactType.getByPrefix(chatMessage.getContactId()).ordinal());
        chatMessage.setMessageContent(messageContent);
        chatMessage.setMessageType(messageType);
        chatMessage.setFileSize(fileSize);
        chatMessage.setFileName(fileName);
        chatMessage.setFileType(fileType);
        Message<?> msg = chatMessageService.saveMessage(chatMessage, tokenObj);
        if (Consts.ROBOT_UID.equals(msg.getContactId()) && type == MessageType.CHAT) {
            chatMessageService.saveMessage4RobotAsync(tokenObj.getUserId(), messageContent);
        }
        return Result.success(msg);
    }

    @PostMapping("/uploadFile")
    public Result uploadFile(@NotNull Long messageId, @NotNull MultipartFile file, MultipartFile cover) throws NoAuthException, BusinessException, IOException {
        log.info("收到文件上传请求{}", file.getOriginalFilename());
        UserInfoToken tokenObj = getTokenObj();
        chatMessageService.uploadFile(tokenObj.getUserId(), messageId, file, cover);
        return Result.success();
    }

    /**
     * @param id 如获得头像，请传递对应的uId/gId；如获得消息文件，请传递messageId
     */
    @GetMapping("/download")
    public void downloadFile(@RequestParam @NotNull String id, @RequestParam @NotNull Boolean wantCover) throws IOException {
        UserInfoToken tokenObj = getTokenObj();
        File file;
        String fileName;
        String mimeType;
        if (!StringTools.isNumber(id)) {
            fileName = id + (wantCover ?
                    Consts.IMAGE_SMALL_SUFFIX : Consts.IMAGE_SUFFIX);
            String fullPath = appConfig.getProjectFolder() + Consts.FOLDER_FILE_AVATAR + "/" + fileName;
            file = new File(fullPath);
            mimeType = Consts.IMAGE_MIME;
        } else {
            Object[] res = chatMessageService.download(tokenObj, Long.parseLong(id), wantCover);
            if (res[0] instanceof String
                    && res[1] instanceof File
                    && res[2] instanceof String) {
                fileName = (String) res[0];
                file = (File) res[1];
                mimeType = (String) res[2];
            } else
                throw new IOException();
        }
        if (!file.exists() || file.length() <= 0) {
            throw new IOException();
        }
        resp.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(fileName, StandardCharsets.UTF_8) + "\"");
        resp.setContentType(mimeType);
        resp.setContentLengthLong(file.length());
        try (FileInputStream fileInputStream = new FileInputStream(file);
             OutputStream outputStream = resp.getOutputStream()) {
            byte[] bytes = new byte[(int) (Consts.BYTES_PER_KB * 10)];
            int bytesRead;
            while ((bytesRead = fileInputStream.read(bytes)) != -1)
                outputStream.write(bytes, 0, bytesRead);
            outputStream.flush();
        }
    }
}
